using MultiAgentsClient.ChatDataStructures;
using MultiAgentsClient.Manager.DataModel;
using MultiAgentsClient.Service.SignalRService;
using MultiAgentsClient.Service.WorkflowEngine;
using MultiAgentsClient.Service.WorkflowEngine.BuiltInNodes;
using MultiAgentsClient.Shared;
using MultiAgentsShared;

using ApiRequest = MultiAgentsClient.Service.SignalRService.SignalRWorkflowService.ApiRequestType;

namespace MultiAgentsClient.Manager;

public class WorkflowOperator : ManagerBase
{
    private readonly SignalRWorkflowService _signalRComService;
    private readonly WorkflowDataModel _workflowDataModel;
    private readonly SystematicNotificationDataModel _systematicNotificationDataModel;
    private readonly UserDataModel userDataModel;
    private readonly SystemConfigDataModel systemConfigDataModel;

    public record ExecuteEventWorkflowCommand(int NotificationId);

    public WorkflowOperator(SystemConfigDataModel systemConfigDataModel, SignalRWorkflowService signalRWorkflowService, WorkflowDataModel workflowDataModel, SystematicNotificationDataModel systematicNotificationDataModel, UserDataModel userDataModel)
    {
        _signalRComService = signalRWorkflowService;
        _workflowDataModel = workflowDataModel;
        _systematicNotificationDataModel = systematicNotificationDataModel;
        this.userDataModel = userDataModel;
        this.systemConfigDataModel = systemConfigDataModel;

        // Node Requests
        eventBus.Subscribe<NodeLlmRequest>(cmd => { Task.Run(() => NodeLlmRequest(cmd)); });
        eventBus.Subscribe<NodeLLMSwitchRequest>(cmd => { Task.Run(() => NodeLLMSwitchRequestCommandHandler(cmd)); });
        eventBus.Subscribe<NodeParameterExtractionRequest>(cmd => { Task.Run(() => NodeParameterExtractionRequestCommandHandler(cmd)); });
        eventBus.Subscribe<ExecuteEventWorkflowCommand>(cmd => { Task.Run(() => ExecuteEventWorkflow(cmd)); });
    }

    private async Task NodeLlmRequest(NodeLlmRequest cmd)
    {
        await _signalRComService.SendSignalRRequest(ApiRequest.LlmNodeRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "nodeId", cmd.NodeId },
                { "msgs", cmd.messages },
                { "model", cmd.gptModel },
                { "temperature", cmd.temperature },
            });
    }

    private async Task NodeLLMSwitchRequestCommandHandler(NodeLLMSwitchRequest cmd)
    {
        await _signalRComService.SendSignalRRequest(ApiRequest.LLMSwitchNodeRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "nodeId", cmd.NodeId },
                { "message", cmd.Message },
                { "categories", cmd.Categories },
            });
    }

    private async Task NodeParameterExtractionRequestCommandHandler(NodeParameterExtractionRequest cmd)
    {
        await _signalRComService.SendSignalRRequest(ApiRequest.ParameterExtractionNodeRequest.ToString(), new Dictionary<string, object>()
            {
                { "sessionId", systemConfigDataModel.sessionId },
                { "userId", userDataModel.Id },
                { "nodeId", cmd.NodeId },
                { "context", cmd.Context },
                { "descriptions", cmd.Descriptions },
            });
    }

    public async void ExecuteEventWorkflow(ExecuteEventWorkflowCommand cmd)
    {
        WorkflowNotification notification = _systematicNotificationDataModel.notificationList.Find(notification => notification.id == cmd.NotificationId) ?? throw new Exception("Should not happen.");
        _systematicNotificationDataModel.notificationList.Remove(notification);
        Dictionary<string, object> workflowParams = notification.content.ToDictionary(kv => kv.Key, kv => (object)kv.Value);

        var workflowConfig = _workflowDataModel[notification.workflowId];

        if (workflowConfig == null || workflowConfig.workflowType != BehaviorTreeConfig.WorkflowType.EventTriggerWorkflow)
        {
            Debug.LogError("Should not happen.");
            return;
        }

        BehaviorTreeSession workflowSession = new(0, workflowConfig);

        GitlabNode gitlabNode = (GitlabNode)workflowSession.behaviorTreeConfig.TriggerNode;

        gitlabNode.PassParams(workflowParams);

        await workflowSession.RunAsync();
    }

    public async void ExecuteManualWorkflow(int workflowId, string userInput, List<LlmMessageSimp>? chatHistory, int chatRoomId)
    {
        BehaviorTreeConfig workflowConfig = _workflowDataModel[workflowId];

        if (workflowConfig == null)
        {
            Debug.LogError("Should not happen.");
            return;
        }

        if (workflowConfig.workflowType != BehaviorTreeConfig.WorkflowType.ManualTriggerWorkflow)
        {
            Debug.LogError("Should not happen.");
            return;
        }

        BehaviorTreeSession workflowSession = new(chatRoomId, workflowConfig);

        //pass in userInput
        UserInputNode userInputNode = (UserInputNode)workflowSession.behaviorTreeConfig.TriggerNode;
        userInputNode.PassUserInput(userInput, chatHistory);

        await workflowSession.RunAsync();
    }
}
